#include "mysql_opt.h"
#include "generate_random.h"

MysqlOpt::MysqlOpt(const char* _host,const char* _username,const char* _passwd,
                    const char* _datebase, unsigned int _port)
        :host(_host),username(_username),passwd(_passwd),datebase(_datebase),
        port(_port)
{
}

bool MysqlOpt::mysql_connect()
{
    //建立连接
    conn = mysql_init(NULL);
    if (!conn)
    {
        cout << "init fail!" << endl;
        return false;
    }
    if (!mysql_real_connect(conn, host, username, passwd, datebase, port, nullptr, 0))
    {
        cout << "connection fail!" << endl;
        return false;
    }
    return true;    
}

bool MysqlOpt::mysql_create_table()
{
    //列名称可不使用引号,也可使用反引号（`id`）
    //列名称不能使用单引号（'id'）或双引号（"id"）
    //列名和表名应该使用反引号（`）来避免与 SQL 保留字冲突，而不是双引号（" "）,反引号表示标识符。
    //双引号在 MySQL 中默认表示字符串，单引号等效于双引号，二者作用相同
    string s = "create table if not exists type(`id` INT NOT NULL AUTO_INCREMENT,"
            "`name` varchar(16),`tinyint` tinyint,`smallint` smallint,"
            "`mediumint` mediumint,`int` int,`bigint` bigint,"
            "`float` float,`double` double,"
            "`char` char(10),`varchar` varchar(10),"
            "`time` time,`date` date,`datetime` datetime,`timestamp` timestamp,"
            "PRIMARY KEY (id))";
    if (mysql_query(conn, s.c_str()) != 0)
    {
        cout << "query: " << s << " fail!" << endl;
        return false;
    }
    cout << "query: " << s << " ok!" << endl;
    return true;
}

//向数据库插入num条记录
bool MysqlOpt::mysql_insert_data(int num)
{
    GenerateRandom random;
    for (int i = 0; i < num; i++)
    {
        // mysql整数类型TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT
        //  tinyint 1字节 定义范围[-128,127]
        int tinyint = random.generate_num(INT8_MIN, INT8_MAX);
        // smallint 2字节 定义范围[-32768,32767]
        int smallint = random.generate_num(INT16_MIN, INT16_MAX);
        // mediumint 3字节 定义范围[-8388608,8388607]
        int mediumint = random.generate_num(-8388608, 8388607);
        // int 4字节 定义范围[-2147483648,2147483647]
        int _int = random.generate_num(INT32_MIN, INT32_MAX);
        // bigint 8字节 定义范围[-9223372036854775808,9223372036854775807]
        long long bigint = random.generate_num(INT64_MIN, INT64_MAX);
        // cout<<"tinyint:"<<tinyint<<endl;
        // cout<<"smallint:"<<smallint<<endl;
        // cout<<"mediumint:"<<mediumint<<endl;
        // cout<<"_int:"<<_int<<endl;
        // cout<<"bigint:"<<bigint<<endl;

        // mysql浮点数类型float、double
        // float [1.00,99999.00]
        float _float = random.generate_double(1.00, 99999.00);
        // double [1.0,99999.0]
        double _double = random.generate_double(1.00, 99999.00);
        // cout<<"_float:"<<_float<<endl;
        // cout<<"_double:"<<_double<<endl;

        // mysql定点数DECIMAL
        // decimal(5,2) [-999.99,999.99]
        double _decimal = random.generate_double(-999.99, 999.99);
        // cout<<"_decimal:"<<_decimal<<endl;

        //日期与时间类型YEAR,DATE,TIME,DATETIME,TIMESTAMP
        string current_time = "NOW()";

        //字符串，定长字符串char(10)，可变字符串varchar(10)
        std::string _char = random.generate_string(10);
        std::string _varchar = random.generate_string(10);
        // cout<<"_char:"<<_char<<endl;
        // cout<<"_varchar:"<<_varchar<<endl;

        //插入
        // CURRENT_TIME()、CURRENT_DATE()
        // 所有元素初始化为 0，即空字符'\0';
        //这是因为使用大括号进行初始化时，如果只提供了部分初始化，剩余的元素会被设置为零。
        // char buffer[50];这样定义时不会进行初始化，内容未定义
        //推荐这种写法；
        char query_str[1000] = {0};
        //.2f 时，输出会四舍五入到小数点后两位
        sprintf(query_str, "insert into type (`tinyint`,`smallint`,`mediumint`,"
                        "`int`,`bigint`,"
                        "`float`,`double`,`decimal`,"
                        "`char`,`varchar`,"
                        "`time`,`date`,`datetime`,`timestamp`) values "
                        "(%d,%d,%d,%d,%lld,%f,%lf,%.2f,'%s','%s',%s,%s,%s,%s)",
                tinyint, smallint, mediumint, _int, bigint,
                _float, _double,_decimal,
                _char.c_str(), _varchar.c_str(),
                current_time.c_str(), current_time.c_str(),
                current_time.c_str(), current_time.c_str());

        if (mysql_query(conn, query_str) != 0)
        {
            cout << "query: " << query_str << " fail!" << endl;
            return false;
        }
        //cout<<"query: "<<query_str<<" ok"<<endl;
        cout <<"成功插入第"<<i+1<<"条数据"<< endl;
    }
    return true;
}

void MysqlOpt::mysql_set_character_set(const char* character_set)
{
    ::mysql_set_character_set(conn, character_set);
}

void MysqlOpt::mysql_close()
{
    ::mysql_close(conn);
}

MysqlOpt::~MysqlOpt()
{
    if(!conn)
    {
        mysql_close();
    }
}
